home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Datafile PD-CD 1 Issue 2
/
PDCD-1 - Issue 02.iso
/
_utilities
/
utilities
/
001
/
meschach
/
!Meschach
/
c
/
sptort
< prev
next >
Wrap
Text File
|
1994-02-28
|
11KB
|
486 lines
/**************************************************************************
**
** Copyright (C) 1993 David E. Steward & Zbigniew Leyk, all rights reserved.
**
** Meschach Library
**
** This Meschach Library is provided "as is" without any express
** or implied warranty of any kind with respect to this software.
** In particular the authors shall not be liable for any direct,
** indirect, special, incidental or consequential damages arising
** in any way from use of the software.
**
** Everyone is granted permission to copy, modify and redistribute this
** Meschach Library, provided:
** 1. All copies contain this copyright notice.
** 2. All modified copies shall carry a notice stating who
** made the last modification and the date of such modification.
** 3. No charge is made for this software or works derived from it.
** This clause shall not be construed as constraining other software
** distributed on the same medium as this software, nor is a
** distribution fee considered a charge.
**
***************************************************************************/
/*
This file contains tests for the sparse matrix part of Meschach
*/
#include <stdio.h>
#include <math.h>
#include "matrix2.h"
#include "sparse2.h"
#include "iter.h"
#define errmesg(mesg) printf("Error: %s error: line %d\n",mesg,__LINE__)
#define notice(mesg) printf("# Testing %s...\n",mesg);
/* for iterative methods */
#if REAL == DOUBLE
#define EPS 1e-7
#elif REAL == FLOAT
#define EPS 1e-3
#endif
int chk_col_access(A)
SPMAT *A;
{
int i, j, nxt_idx, nxt_row, scan_cnt, total_cnt;
SPROW *r;
row_elt *e;
if ( ! A )
error(E_NULL,"chk_col_access");
if ( ! A->flag_col )
return FALSE;
/* scan down each column, counting the number of entries met */
scan_cnt = 0;
for ( j = 0; j < A->n; j++ )
{
i = -1;
nxt_idx = A->start_idx[j];
nxt_row = A->start_row[j];
while ( nxt_row >= 0 && nxt_idx >= 0 && nxt_row > i )
{
i = nxt_row;
r = &(A->row[i]);
e = &(r->elt[nxt_idx]);
nxt_idx = e->nxt_idx;
nxt_row = e->nxt_row;
scan_cnt++;
}
}
total_cnt = 0;
for ( i = 0; i < A->m; i++ )
total_cnt += A->row[i].len;
if ( total_cnt != scan_cnt )
return FALSE;
else
return TRUE;
}
void main(argc, argv)
int argc;
char *argv[];
{
VEC *x, *y, *z, *u, *v;
Real s1, s2;
PERM *pivot;
SPMAT *A, *B, *C;
SPMAT *B1, *C1;
SPROW *r;
int i, j, k, deg, seed, m, m_old, n, n_old;
mem_info_on(TRUE);
setbuf(stdout, (char *)NULL);
/* get seed if in argument list */
if ( argc == 1 )
seed = 1111;
else if ( argc == 2 && sscanf(argv[1],"%d",&seed) == 1 )
;
else
{
printf("usage: %s [seed]\n", argv[0]);
exit(0);
}
srand(seed);
/* set up two random sparse matrices */
m = 120;
n = 100;
deg = 8;
notice("allocating sparse matrices");
A = sp_get(m,n,deg);
B = sp_get(m,n,deg);
notice("setting and getting matrix entries");
for ( k = 0; k < m*deg; k++ )
{
i = (rand() >> 8) % m;
j = (rand() >> 8) % n;
sp_set_val(A,i,j,rand()/((Real)MAX_RAND));
i = (rand() >> 8) % m;
j = (rand() >> 8) % n;
sp_set_val(B,i,j,rand()/((Real)MAX_RAND));
}
for ( k = 0; k < 10; k++ )
{
s1 = rand()/((Real)MAX_RAND);
i = (rand() >> 8) % m;
j = (rand() >> 8) % n;
sp_set_val(A,i,j,s1);
s2 = sp_get_val(A,i,j);
if ( fabs(s1 - s2) >= MACHEPS )
break;
}
if ( k < 10 )
errmesg("sp_set_val()/sp_get_val()");
/* test copy routines */
notice("copy routines");
x = v_get(n);
y = v_get(m);
z = v_get(m);
/* first copy routine */
C = sp_copy(A);
for ( k = 0; k < 100; k++ )
{
v_rand(x);
sp_mv_mlt(A,x,y);
sp_mv_mlt(C,x,z);
if ( v_norm_inf(v_sub(y,z,z)) >= MACHEPS*deg*m )
break;
}
if ( k < 100 )
{
errmesg("sp_copy()/sp_mv_mlt()");
printf("# Error in A.x (inf norm) = %g [cf MACHEPS = %g]\n",
v_norm_inf(z), MACHEPS);
}
/* second copy routine
-- note that A & B have different sparsity patterns */
mem_stat_mark(1);
sp_copy2(A,B);
mem_stat_free(1);
for ( k = 0; k < 10; k++ )
{
v_rand(x);
sp_mv_mlt(A,x,y);
sp_mv_mlt(B,x,z);
if ( v_norm_inf(v_sub(y,z,z)) >= MACHEPS*deg*m )
break;
}
if ( k < 10 )
{
errmesg("sp_copy2()/sp_mv_mlt()");
printf("# Error in A.x (inf norm) = %g [cf MACHEPS = %g]\n",
v_norm_inf(z), MACHEPS);
}
/* now check compacting routine */
notice("compacting routine");
sp_compact(B,0.0);
for ( k = 0; k < 10; k++ )
{
v_rand(x);
sp_mv_mlt(A,x,y);
sp_mv_mlt(B,x,z);
if ( v_norm_inf(v_sub(y,z,z)) >= MACHEPS*deg*m )
break;
}
if ( k < 10 )
{
errmesg("sp_compact()");
printf("# Error in A.x (inf norm) = %g [cf MACHEPS = %g]\n",
v_norm_inf(z), MACHEPS);
}
for ( i = 0; i < B->m; i++ )
{
r = &(B->row[i]);
for ( j = 0; j < r->len; j++ )
if ( r->elt[j].val == 0.0 )
break;
}
if ( i < B->m )
{
errmesg("sp_compact()");
printf("# Zero entry in compacted matrix\n");
}
/* check column access paths */
notice("resizing and access paths");
m_old = A->m-1;
n_old = A->n-1;
A = sp_resize(A,A->m+10,A->n+10);
for ( k = 0 ; k < 20; k++ )
{
i = m_old + ((rand() >> 8) % 10);
j = n_old + ((rand() >> 8) % 10);
s1 = rand()/((Real)MAX_RAND);
sp_set_val(A,i,j,s1);
if ( fabs(s1 - sp_get_val(A,i,j)) >= MACHEPS )
break;
}
if ( k < 20 )
errmesg("sp_resize()");
sp_col_access(A);
if ( ! chk_col_access(A) )
{
errmesg("sp_col_access()");
}
sp_diag_access(A);
for ( i = 0; i < A->m; i++ )
{
r = &(A->row[i]);
if ( r->diag != sprow_idx(r,i) )
break;
}
if ( i < A->m )
{
errmesg("sp_diag_access()");
}
/* test both sp_mv_mlt() and sp_vm_mlt() */
x = v_resize(x,B->n);
y = v_resize(y,B->m);
u = v_get(B->m);
v = v_get(B->n);
for ( k = 0; k < 10; k++ )
{
v_rand(x);
v_rand(y);
sp_mv_mlt(B,x,u);
sp_vm_mlt(B,y,v);
if ( fabs(in_prod(x,v) - in_prod(y,u)) >=
MACHEPS*v_norm2(x)*v_norm2(u)*5 )
break;
}
if ( k < 10 )
{
errmesg("sp_mv_mlt()/sp_vm_mlt()");
printf("# Error in inner products = %g [cf MACHEPS = %g]\n",
fabs(in_prod(x,v) - in_prod(y,u)), MACHEPS);
}
SP_FREE(A);
SP_FREE(B);
SP_FREE(C);
/* now test Cholesky and LU factorise and solve */
notice("sparse Cholesky factorise/solve");
A = iter_gen_sym(120,8);
B = sp_copy(A);
spCHfactor(A);
x = v_resize(x,A->m);
y = v_resize(y,A->m);
v_rand(x);
sp_mv_mlt(B,x,y);
z = v_resize(z,A->m);
spCHsolve(A,y,z);
v = v_resize(v,A->m);
sp_mv_mlt(B,z,v);
/* compute residual */
v_sub(y,v,v);
if ( v_norm2(v) >= MACHEPS*v_norm2(y)*10 )
{
errmesg("spCHfactor()/spCHsolve()");
printf("# Sparse Cholesky residual = %g [cf MACHEPS = %g]\n",
v_norm2(v), MACHEPS);
}
/* compute error in solution */
v_sub(x,z,z);
if ( v_norm2(z) > MACHEPS*v_norm2(x)*10 )
{
errmesg("spCHfactor()/spCHsolve()");
printf("# Solution error = %g [cf MACHEPS = %g]\n",
v_norm2(z), MACHEPS);
}
/* now test symbolic and incomplete factorisation */
SP_FREE(A);
A = sp_copy(B);
mem_stat_mark(2);
spCHsymb(A);
mem_stat_mark(2);
spICHfactor(A);
spCHsolve(A,y,z);
v = v_resize(v,A->m);
sp_mv_mlt(B,z,v);
/* compute residual */
v_sub(y,v,v);
if ( v_norm2(v) >= MACHEPS*v_norm2(y)*5 )
{
errmesg("spCHsymb()/spICHfactor()");
printf("# Sparse Cholesky residual = %g [cf MACHEPS = %g]\n",
v_norm2(v), MACHEPS);
}
/* compute error in solution */
v_sub(x,z,z);
if ( v_norm2(z) > MACHEPS*v_norm2(x)*10 )
{
errmesg("spCHsymb()/spICHfactor()");
printf("# Solution error = %g [cf MACHEPS = %g]\n",
v_norm2(z), MACHEPS);
}
/* now test sparse LU factorisation */
notice("sparse LU factorise/solve");
SP_FREE(A);
SP_FREE(B);
A = iter_gen_nonsym(100,100,8,1.0);
B = sp_copy(A);
x = v_resize(x,A->n);
z = v_resize(z,A->n);
y = v_resize(y,A->m);
v = v_resize(v,A->m);
v_rand(x);
sp_mv_mlt(B,x,y);
pivot = px_get(A->m);
mem_stat_mark(3);
spLUfactor(A,pivot,0.1);
spLUsolve(A,pivot,y,z);
mem_stat_free(3);
sp_mv_mlt(B,z,v);
/* compute residual */
v_sub(y,v,v);
if ( v_norm2(v) >= MACHEPS*v_norm2(y)*A->m )
{
errmesg("spLUfactor()/spLUsolve()");
printf("# Sparse LU residual = %g [cf MACHEPS = %g]\n",
v_norm2(v), MACHEPS);
}
/* compute error in solution */
v_sub(x,z,z);
if ( v_norm2(z) > MACHEPS*v_norm2(x)*100*A->m )
{
errmesg("spLUfactor()/spLUsolve()");
printf("# Sparse LU solution error = %g [cf MACHEPS = %g]\n",
v_norm2(z), MACHEPS);
}
/* now check spLUTsolve */
mem_stat_mark(4);
sp_vm_mlt(B,x,y);
spLUTsolve(A,pivot,y,z);
sp_vm_mlt(B,z,v);
mem_stat_free(4);
/* compute residual */
v_sub(y,v,v);
if ( v_norm2(v) >= MACHEPS*v_norm2(y)*A->m )
{
errmesg("spLUTsolve()");
printf("# Sparse LU residual = %g [cf MACHEPS = %g]\n",
v_norm2(v), MACHEPS);
}
/* compute error in solution */
v_sub(x,z,z);
if ( v_norm2(z) > MACHEPS*v_norm2(x)*100*A->m )
{
errmesg("spLUTsolve()");
printf("# Sparse LU solution error = %g [cf MACHEPS = %g]\n",
v_norm2(z), MACHEPS);
}
/* algebraic operations */
notice("addition,subtraction and multiplying by a number");
SP_FREE(A);
SP_FREE(B);
m = 120;
n = 120;
deg = 5;
A = sp_get(m,n,deg);
B = sp_get(m,n,deg);
C = sp_get(m,n,deg);
C1 = sp_get(m,n,deg);
for ( k = 0; k < m*deg; k++ )
{
i = (rand() >> 8) % m;
j = (rand() >> 8) % n;
sp_set_val(A,i,j,rand()/((Real)MAX_RAND));
i = (rand() >> 8) % m;
j = (rand() >> 8) % n;
sp_set_val(B,i,j,rand()/((Real)MAX_RAND));
}
s1 = mrand();
B1 = sp_copy(B);
mem_stat_mark(1);
sp_smlt(B,s1,C);
sp_add(A,C,C1);
sp_sub(C1,A,C);
sp_smlt(C,-1.0/s1,C);
sp_add(C,B1,C);
s2 = 0.0;
for (k=0; k < C->m; k++) {
r = &(C->row[k]);
for (j=0; j < r->len; j++) {
if (s2 < fabs(r->elt[j].val))
s2 = fabs(r->elt[j].val);
}
}
if (s2 > MACHEPS*A->m) {
errmesg("add, sub, mlt sparse matrices (args not in situ)\n");
printf(" difference = %g [MACEPS = %g]\n",s2,MACHEPS);
}
sp_mltadd(A,B1,s1,C1);
sp_sub(C1,A,A);
sp_smlt(A,1.0/s1,C1);
sp_sub(C1,B1,C1);
mem_stat_free(1);
s2 = 0.0;
for (k=0; k < C1->m; k++) {
r = &(C1->row[k]);
for (j=0; j < r->len; j++) {
if (s2 < fabs(r->elt[j].val))
s2 = fabs(r->elt[j].val);
}
}
if (s2 > MACHEPS*A->m) {
errmesg("add, sub, mlt sparse matrices (args not in situ)\n");
printf(" difference = %g [MACEPS = %g]\n",s2,MACHEPS);
}
V_FREE(x);
V_FREE(y);
V_FREE(z);
V_FREE(u);
V_FREE(v);
PX_FREE(pivot);
SP_FREE(A);
SP_FREE(B);
SP_FREE(C);
SP_FREE(B1);
SP_FREE(C1);
printf("# Done testing (%s)\n",argv[0]);
mem_info();
}